package com.ctc;

public class CTCSlave extends CTCDevice
{
    /**
     * 构造函数
     *
     * @param player     P位
     * @param serialName 串口名称
     * @param productID  产品ID
     * @param deviceID   设备ID
     */
    public CTCSlave(byte player, String serialName, long productID, byte[] deviceID)
    {
        super(player, serialName, 38400);
        slaveDeviceId = deviceID;
        slaveProductId = productID;
        slaveCTCVersion = CTC_SLAVE_VERSION;
    }

    /**
     * 获取从设备状态
     *
     * @return 从设备状态
     */
    public byte getSlaveState()
    {
        return slaveState;
    }

    /**
     * 设置监听
     *
     * @param listener 监听
     */
    public void setListener(CTCEvent.ISlave listener)
    {
        this.listener = listener;
    }

    @Override
    protected void handleReceive(DataPacket dataPacket)
    {
        if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_HANDSHAKE))
        {//握手应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_HANDSHAKE)
            {
                logE(String.format("CTC Handshake Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            handshake = true;
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnConnectStateChange(CTCClientConnState.Connected);
            masterCTCVersion = CRC.bytesToUint16(dataPacket.getData()[20], dataPacket.getData()[21]);
            rspHandshake();
            handleOnHandshake(dataPacket.getData());
            return;
        }
        //如果没有完成握手就不处理其它指令
        if (!handshake)
        {
            return;
        }
        if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_HEARTBEAT))
        {//心跳应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_HEARTBEAT)
            {
                logE(String.format("CTC Heartbeat Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            rspHeartbeat();
            byte masterState = dataPacket.getData()[0];
            if (this.masterState != masterState)
            {
                this.masterState = masterState;
                handleOnMasterStateChange(dataPacket.getData());
            }
        }

        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_METER_READ))
        {//读表数据
            if (dataPacket.getDataLength() != 0)
            {
                logE(String.format("CTC Meter Data Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnMeterRead();
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_COIN_IN))
        {//投币应答
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_COIN_IN)
            {
                logE(String.format("CTC Coin In Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnCoinIn(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_CHANNEL_SEL))
        {// 通道选择请求
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_CHANNEL_SEL)
            {
                logE(String.format("CTC Channel Sel Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnSelectChannel(dataPacket.getData());
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_QUERY_COIN))
        {// 查询单价请求
            if (dataPacket.getDataLength() != 0)
            {
                logE(String.format("CTC Query Coin Rsp Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;

            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnQueryCoin();
        }
        else if (checkInst(dataPacket.getInst(), CTCMsg.CTC_CMD_SET_COIN))
        {// 设置单价请求
            if (dataPacket.getDataLength() != CTCMsg.CTC_CMDLEN_SET_COIN)
            {
                logE(String.format("CTC Set Coin Price Length Error:%s", dataPacket.getDataLength()));
                sendACK(dataPacket, CTCMsg.CTC_ACK_LENGTH_ERR);
                return;
            }
            sendACK(dataPacket, CTCMsg.CTC_ACK_SUCCESS);
            handleOnSetCoinPrice(dataPacket.getData());
        }
        else
        {// 不支持的指令
            logE(String.format("CTC Received Unsupported Command ID:%s", CRC.toHexStringTrim(dataPacket.getInst())));
            sendACK(dataPacket, CTCMsg.CTC_ACK_UNSUPPORTED);
        }
    }

    /**
     * 回应握手
     */
    protected void rspHandshake()
    {
        logI("回应握手");
        byte[] data = new byte[22];
        System.arraycopy(CRC.uint32ToBytes(slaveProductId), 0, data, 0, 4);
        System.arraycopy(slaveDeviceId, 0, data, 4, 16);
        System.arraycopy(CRC.uint16ToBytes(CTC_SLAVE_VERSION), 0, data, 20, 2);
        send(new DataPacket(player, CTCMsg.CTC_CMD_HANDSHAKE_RSP, sendTransactionId++, data));
    }

    /// <summary>
    /// 回应心跳
    /// </summary>
    protected void rspHeartbeat()
    {
        byte[] data = new byte[3];
        data[0] = slaveState;
        System.arraycopy(CRC.uint16ToBytes(slaveErrorCode), 0, data, 1, 2);
        send(new DataPacket(player, CTCMsg.CTC_CMD_HEARTBEAT_RSP, sendTransactionId++, data));
    }

    /**
     * 回应投币
     *
     * @param isAccept 0=成功接收,1=拒绝接收
     * @param orderID  投币时传递的交易ID
     */
    public void rspCoinIn(byte isAccept, byte[] orderID)
    {
        byte[] data = new byte[17];
        data[0] = isAccept;
        System.arraycopy(orderID, 0, data, 1, 16);
        send(new DataPacket(player, CTCMsg.CTC_CMD_COIN_IN_RSP, sendTransactionId++, data));
    }

    /**
     * 回应查询币每局多少币请求
     *
     * @param number 每局多少币
     */
    public void rspQueryCoin(int number)
    {
        byte[] data = new byte[2];
        System.arraycopy(CRC.uint16ToBytes(number), 0, data, 0, 2);
        send(new DataPacket(player, CTCMsg.CTC_CMD_QUERY_COIN_RSP, sendTransactionId++, data));
    }

    /**
     * 回应抄表指令
     *
     * @param data 抄表数据<br>
     *             5个byte为一组,一共10组50个byte<br>
     *             0:类型<br>
     *             1-4:数据<br>
     *             类型<br>
     *             0=投币总数,1=电子币总数,2=实物币总数<br>
     *             10=出票总数,11=出电子票总数,12=出实物票总数<br>
     *             20=出蓝票总数,21=出电子蓝票总数,22=出实物蓝票总数<br>
     *             30=总出卡片数<br>
     *             100=出礼品1总数,101=出实物礼品2总数,102=出实物礼品2总数,103=出实物礼品4总数,104=出实物礼品5总数,...130=出实物礼品31总数<br>
     *             255=数据结束(无效后面不能再放有效数据)<br>
     */
    public void rspMeterRead(byte[] data)
    {
        send(new DataPacket(player, CTCMsg.CTC_CMD_METER_DATA, sendTransactionId++, data));
    }

    /**
     * 实物奖励上报
     *
     * @param type   0=实物币,1=实物彩票,2=实体蓝票,3=实体卡片,100=实物礼品1,101=实物礼品2...130=实物礼品31
     * @param number 上报数量
     */
    public void sendPhysicalReport(byte type, long number)
    {
        byte[] data = new byte[5];
        data[0] = type;
        System.arraycopy(CRC.uint32ToBytes(number), 0, data, 1, 4);
        send(new DataPacket(player, CTCMsg.CTC_CMD_PHYSICAL_REPORT, sendTransactionId++, data));
    }

    /**
     * 游戏有奖励给玩家(游戏机到卡头)
     *
     * @param type   0=奖励彩票,1=奖励蓝票,10=游戏任务得分
     * @param number 奖励的数量
     */
    public void sendReward(byte type, long number)
    {
        byte[] data = new byte[5];
        data[0] = type;
        System.arraycopy(CRC.uint32ToBytes(number), 0, data, 1, 4);
        send(new DataPacket(player, CTCMsg.CTC_CMD_REWARD, sendTransactionId++, data));
    }

    /**
     * 游戏氛围事件(游戏机到卡头)
     *
     * @param level  0开始,数字越大氛围越强烈
     * @param type   0=奖励彩票,1=奖励蓝票,10=游戏任务得分,100=奖励实物
     * @param number 产生的奖励相关的数量
     */
    public void sendAtmosphere(byte level, byte type, long number)
    {
        byte[] data = new byte[7];
        System.arraycopy(CRC.uint16ToBytes(level), 0, data, 0, 2);
        data[2] = type;
        System.arraycopy(CRC.uint32ToBytes(number), 0, data, 3, 4);
        send(new DataPacket(player, CTCMsg.CTC_CMD_ATMOSPHEREEVENT, sendTransactionId++, data));
    }

    /**
     * 变更状态
     *
     * @param state     0=卡头可正常消费,1=卡头不可进行消费
     * @param errorCode 0=无故障,非0代表有故障
     */
    public void changeState(byte state, int errorCode)
    {
        slaveState = state;
        slaveErrorCode = errorCode;
        rspHeartbeat();
    }

    /**
     * 主设备状态改变事件
     *
     * @param data 数据
     */
    protected void handleOnMasterStateChange(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onMasterStateChange(player, data);
        }
    }

    /**
     * 抄表
     */
    protected void handleOnMeterRead()
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onMeterRead(player);
        }
    }

    /**
     * 查询硬币
     */
    protected void handleOnQueryCoin()
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onQueryCoin(player);
        }
    }

    /**
     * 硬币插入事件
     *
     * @param data 数据
     */
    protected void handleOnCoinIn(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onCoinIn(player, data);
        }
    }

    /**
     * 握手事件
     *
     * @param data 数据
     */
    protected void handleOnHandshake(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onHandshake(player, data);
        }
    }

    /**
     * 设置硬币价格事件
     *
     * @param data 数据
     */
    protected void handleOnSetCoinPrice(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onSetCoinPrice(player, data);
        }
    }

    /**
     * 选择通道事件
     *
     * @param data 数据
     */
    protected void handleOnSelectChannel(byte[] data)
    {
        if (listener != null)
        {
            ((CTCEvent.ISlave) listener).onSelectChannel(player, data);
        }
    }
}
